home *** CD-ROM | disk | FTP | other *** search
/ LG Super CD / LG Super CD.iso / bitpim / bitpim-0.62-setup.exe / {app} / bitpim.exe / guiwidgets.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2003-11-06  |  93.7 KB  |  2,307 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.3)
  3.  
  4. import os
  5. import calendar
  6. import time
  7. import copy
  8. from wxPython.wx import *
  9. from wxPython.grid import *
  10. from wxPython.lib.mixins.listctrl import wxColumnSorterMixin, wxListCtrlAutoWidthMixin
  11. from wxPython.lib.intctrl import *
  12. from wxPython.lib.maskededit import wxMaskedTextCtrl
  13. from wxPython.html import *
  14. import common
  15. import gui
  16. import calendarcontrol
  17. import helpids
  18. import comscan
  19. import comdiagnose
  20. import brewcompressedimage
  21.  
  22. class PhoneDataTable(wxPyGridTableBase):
  23.     CURRENTFILEVERSION = 1
  24.     numbertypetab = ('Home', 'Home2', 'Office', 'Office2', 'Mobile', 'Mobile2', 'Pager', 'Fax', 'Fax2', 'None')
  25.     typesnames = ('type1', 'type2', 'type3', 'type4', 'type5')
  26.     typestypename = wxGRID_VALUE_CHOICE + ':' + ','.join(numbertypetab)
  27.     groupnames = ('group',)
  28.     grouptypenamebase = wxGRID_VALUE_CHOICE + ':'
  29.     intnames = ('msgringtone', 'ringtone', 'serial1', 'serial2')
  30.     boolnames = ('secret',)
  31.     blankentry = {
  32.         'name': '',
  33.         'group': 0,
  34.         'type1': 0,
  35.         'type2': 0,
  36.         'type3': 0,
  37.         'type4': 0,
  38.         'type5': 0,
  39.         'number1': '',
  40.         'number2': '',
  41.         'number3': '',
  42.         'number4': '',
  43.         'number5': '',
  44.         'email1': '',
  45.         'email2': '',
  46.         'email3': '',
  47.         'memo': '',
  48.         'msgringtone': 0,
  49.         'ringtone': 0,
  50.         'secret': False,
  51.         'serial1': 0,
  52.         'serial2': 0,
  53.         'url': '',
  54.         '?offset00f': 0,
  55.         '?offset028': 0,
  56.         '?offset111': 0,
  57.         '?offset20c': 0 }
  58.     
  59.     def __init__(self, mainwindow):
  60.         wxPyGridTableBase.__init__(self)
  61.         self.mainwindow = mainwindow
  62.         self.numrows = 0
  63.         self.numcols = 0
  64.         self.labels = []
  65.         self.roworder = []
  66.         self._data = { }
  67.         self.needswrite = False
  68.         self.sequence = 65535
  69.         self.groupdict = {
  70.             0: {
  71.                 'name': 'No Group',
  72.                 'icon': 0 },
  73.             1: {
  74.                 'name': 'Family',
  75.                 'icon': 1 },
  76.             2: {
  77.                 'name': 'Friends',
  78.                 'icon': 2 },
  79.             3: {
  80.                 'name': 'Colleagues',
  81.                 'icon': 3 },
  82.             4: {
  83.                 'name': 'Business',
  84.                 'icon': 4 },
  85.             5: {
  86.                 'name': 'School',
  87.                 'icon': 5 } }
  88.         self.buildgrouptypename(self.groupdict)
  89.  
  90.     
  91.     def OnIdle(self, _):
  92.         if self.needswrite:
  93.             self.populatefs(self.getdata({ }))
  94.             self.needswrite = False
  95.         
  96.  
  97.     
  98.     def getdata(self, dict):
  99.         dict['phonebook'] = self._data.copy()
  100.         dict['groups'] = self.groupdict.copy()
  101.         return dict
  102.  
  103.     
  104.     def setstandardlabels(self):
  105.         self.addcolumn('name')
  106.         self.addcolumn('group')
  107.         for i in range(1, 6):
  108.             self.addcolumn('type' + `i`)
  109.             self.addcolumn('number' + `i`)
  110.         
  111.  
  112.     
  113.     def addcolumn(self, name):
  114.         self.labels.append(name)
  115.         msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_COLS_APPENDED, 1)
  116.         self.GetView().ProcessTableMessage(msg)
  117.  
  118.     
  119.     def clear(self):
  120.         oldr = self.numrows
  121.         self.numrows = 0
  122.         msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, oldr)
  123.         if oldr:
  124.             self.GetView().ProcessTableMessage(msg)
  125.         
  126.  
  127.     
  128.     def OnDelete(self, rows):
  129.         rows.sort()
  130.         rows.reverse()
  131.         for row in rows:
  132.             del self._data[self.roworder[row]]
  133.             del self.roworder[row]
  134.             self.numrows -= 1
  135.             msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1)
  136.             self.GetView().ProcessTableMessage(msg)
  137.         
  138.         if len(rows):
  139.             self.needswrite = True
  140.         
  141.  
  142.     
  143.     def OnAdd(self, currow):
  144.         self.sequence += 1
  145.         while self.sequence in self._data:
  146.             self.sequence += 1
  147.             continue
  148.             self
  149.         self._data[self.sequence] = self.blankentry.copy()
  150.         if currow + 1 == self.numrows:
  151.             msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1)
  152.             self.roworder.append(self.sequence)
  153.         else:
  154.             msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, currow + 1, 1)
  155.             self.roworder[currow + 1:currow + 1] = [
  156.                 self.sequence]
  157.         self.numrows += 1
  158.         self.GetView().ProcessTableMessage(msg)
  159.         self.needswrite = True
  160.  
  161.     
  162.     def getcolumn(self, name):
  163.         if len(self.labels) == 0:
  164.             self.setstandardlabels()
  165.         
  166.         if name not in self.labels:
  167.             self.addcolumn(name)
  168.         
  169.         return self.labels.index(name)
  170.  
  171.     
  172.     def populatefs(self, dict):
  173.         self.thedir = self.mainwindow.phonebookpath
  174.         
  175.         try:
  176.             os.makedirs(self.thedir)
  177.         except:
  178.             pass
  179.  
  180.         if not os.path.isdir(self.thedir):
  181.             raise Exception("Bad directory for phonebook '" + self.thedir + "'")
  182.         
  183.         for f in os.listdir(self.thedir):
  184.             os.remove(os.path.join(self.thedir, f))
  185.         
  186.         d = { }
  187.         d['phonebook'] = dict['phonebook']
  188.         if dict.has_key('groups'):
  189.             d['groups'] = dict['groups']
  190.         
  191.         common.writeversionindexfile(os.path.join(self.thedir, 'index.idx'), d, self.CURRENTFILEVERSION)
  192.         return dict
  193.  
  194.     
  195.     def getfromfs(self, dict):
  196.         self.thedir = self.mainwindow.phonebookpath
  197.         
  198.         try:
  199.             os.makedirs(self.thedir)
  200.         except:
  201.             pass
  202.  
  203.         if not os.path.isdir(self.thedir):
  204.             raise Exception("Bad directory for phonebook '" + self.thedir + "'")
  205.         
  206.         if os.path.exists(os.path.join(self.thedir, 'index.idx')):
  207.             d = {
  208.                 'result': { } }
  209.             common.readversionedindexfile(os.path.join(self.thedir, 'index.idx'), d, self.versionupgrade, self.CURRENTFILEVERSION)
  210.             dict.update(d['result'])
  211.         else:
  212.             dict['phonebook'] = { }
  213.             dict['groups'] = self.groupdict
  214.         return dict
  215.  
  216.     
  217.     def populate(self, dict):
  218.         self.clear()
  219.         pb = dict['phonebook']
  220.         k = pb.keys()
  221.         k.sort()
  222.         self._data = pb.copy()
  223.         self.roworder = k
  224.         oldrows = self.numrows
  225.         self.numrows = len(k)
  226.         msg = None
  227.         if self.numrows > oldrows:
  228.             msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, self.numrows - oldrows)
  229.         elif self.numrows < oldrows:
  230.             msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_DELETED, self.numrows, oldrows - self.numrows)
  231.         
  232.         if msg is not None:
  233.             self.GetView().ProcessTableMessage(msg)
  234.         
  235.         cols = []
  236.         for e in pb:
  237.             keys = pb[e].keys()
  238.             for k in keys:
  239.                 if k not in cols:
  240.                     cols.append(k)
  241.                     continue
  242.             
  243.         
  244.         cols.sort()
  245.         k2 = []
  246.         for c in cols:
  247.             if c[0] == '?':
  248.                 k2.append(c)
  249.                 continue
  250.             self.getcolumn(c)
  251.         
  252.         k2.sort()
  253.         for c in k2:
  254.             self.getcolumn(c)
  255.         
  256.         self.GetView().FitInside()
  257.         if dict.has_key('groups'):
  258.             self.buildgrouptypename(dict['groups'])
  259.         
  260.  
  261.     
  262.     def versionupgrade(self, dict, version):
  263.         if version == 0:
  264.             version = 1
  265.         
  266.  
  267.     
  268.     def buildgrouptypename(self, dict):
  269.         self.grouptypename = self.grouptypenamebase
  270.         keys = dict.keys()
  271.         keys.sort()
  272.         [] += []([ dict[k]['name'] for k in keys ])
  273.         self.groupdict = dict.copy()
  274.  
  275.     
  276.     def GetNumberRows(self):
  277.         return len(self.roworder)
  278.  
  279.     
  280.     def GetNumberCols(self):
  281.         return len(self.labels)
  282.  
  283.     
  284.     def IsEmptyCell(self, row, col):
  285.         return False
  286.  
  287.     
  288.     def GetValue(self, row, col):
  289.         celldata = self._data[self.roworder[row]][self.labels[col]]
  290.         
  291.         try:
  292.             if self.labels[col] in self.typesnames:
  293.                 return self.numbertypetab[celldata]
  294.             elif self.labels[col] in self.groupnames:
  295.                 if self.groupdict.has_key(celldata):
  296.                     return self.groupdict[celldata]['name']
  297.                 
  298.                 return 'Group #' + `celldata`
  299.             
  300.             return celldata
  301.         except:
  302.             print 'bad request', row, self.labels[col]
  303.             return ''
  304.  
  305.  
  306.     
  307.     def GetTypeName(self, row, col):
  308.         if self.labels[col] in self.typesnames:
  309.             return self.typestypename
  310.         elif self.labels[col] in self.intnames or self.labels[col][0] == '?':
  311.             return wxGRID_VALUE_NUMBER
  312.         elif self.labels[col] in self.boolnames:
  313.             return wxGRID_VALUE_BOOL
  314.         elif self.labels[col] in self.groupnames:
  315.             return self.grouptypename
  316.         
  317.         return wxGRID_VALUE_STRING + ':50'
  318.  
  319.     
  320.     def SetValue(self, row, col, value):
  321.         if self.labels[col] in self.typesnames:
  322.             for i in range(0, len(self.numbertypetab)):
  323.                 if value == self.numbertypetab[i]:
  324.                     value = i
  325.                     break
  326.                     continue
  327.             
  328.         elif self.labels[col] in self.groupnames:
  329.             for i in self.groupdict:
  330.                 if value == self.groupdict[i]['name']:
  331.                     value = i
  332.                     break
  333.                     continue
  334.             
  335.         
  336.         print 'SetValue', row, col, `value`
  337.         self._data[self.roworder[row]][self.labels[col]] = value
  338.         if self.labels[col] == 'name':
  339.             self.GetView().GetGridRowLabelWindow().Refresh()
  340.         
  341.         self.needswrite = 1
  342.  
  343.     
  344.     def GetColLabelValue(self, col):
  345.         return self.labels[col]
  346.  
  347.     
  348.     def GetRowLabelValue(self, row):
  349.         return self._data[self.roworder[row]]['name']
  350.  
  351.     
  352.     def CanGetValueAs(self, row, col, typename):
  353.         return True
  354.  
  355.     
  356.     def CanSetValueAs(self, row, col, typename):
  357.         return self.CanGetValueAs(row, col, typename)
  358.  
  359.  
  360.  
  361. class PhoneGrid(wxGrid):
  362.     
  363.     def __init__(self, mainwindow, parent, id = -1, *args, **kwargs):
  364.         apply(wxGrid.__init__, (self, parent, id) + args, kwargs)
  365.         self.mainwindow = mainwindow
  366.         self.table = PhoneDataTable(mainwindow)
  367.         self.SetTable(self.table, True)
  368.         self.table.setstandardlabels()
  369.         EVT_IDLE(self, self.table.OnIdle)
  370.         EVT_GRID_CELL_LEFT_DCLICK(self, self.OnLeftDClick)
  371.         EVT_KEY_DOWN(self, self.OnKeyDown)
  372.  
  373.     
  374.     def OnKeyDown(self, event):
  375.         if event.KeyCode() != WXK_RETURN:
  376.             event.Skip()
  377.             return None
  378.         
  379.         if event.ControlDown():
  380.             event.Skip()
  381.             return None
  382.         
  383.         self.DisableCellEditControl()
  384.         success = self.MoveCursorRight(event.ShiftDown())
  385.  
  386.     
  387.     def OnLeftDClick(self, _):
  388.         if self.CanEnableCellControl():
  389.             self.EnableCellEditControl()
  390.         
  391.  
  392.     
  393.     def OnDelete(self, _ = None):
  394.         print 'delete - selected cells=', self.GetSelectedCells()
  395.         rows = self.GetSelectedRows()
  396.         self.table.OnDelete(rows)
  397.  
  398.     
  399.     def OnAdd(self, _ = None):
  400.         print 'add, cursor at row', self.GetGridCursorRow()
  401.         self.table.OnAdd(self.GetGridCursorRow())
  402.  
  403.     
  404.     def clear(self):
  405.         self.table.clear()
  406.  
  407.     
  408.     def getdata(self, dict):
  409.         self.table.getdata(dict)
  410.  
  411.     
  412.     def populatefs(self, dict):
  413.         return self.table.populatefs(dict)
  414.  
  415.     
  416.     def populate(self, dict):
  417.         return self.table.populate(dict)
  418.  
  419.     
  420.     def getfromfs(self, dict):
  421.         return self.table.getfromfs(dict)
  422.  
  423.  
  424.  
  425. class LogWindow(wxPanel):
  426.     
  427.     def __init__(self, parent):
  428.         wxPanel.__init__(self, parent, -1, style = wxNO_FULL_REPAINT_ON_RESIZE)
  429.         self.tb = wxTextCtrl(self, 1, style = wxTE_MULTILINE | wxTE_RICH2 | wxTE_READONLY | wxNO_FULL_REPAINT_ON_RESIZE | wxTE_DONTWRAP)
  430.         f = wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)
  431.         ta = wxTextAttr(font = f)
  432.         self.tb.SetDefaultStyle(ta)
  433.         self.sizer = wxBoxSizer(wxVERTICAL)
  434.         self.sizer.Add(self.tb, 1, wxEXPAND)
  435.         self.SetSizer(self.sizer)
  436.         self.SetAutoLayout(True)
  437.         self.sizer.Fit(self)
  438.         EVT_IDLE(self, self.OnIdle)
  439.         self.outstandingtext = ''
  440.  
  441.     
  442.     def OnIdle(self, _):
  443.         if len(self.outstandingtext):
  444.             self.tb.AppendText(self.outstandingtext)
  445.             self.outstandingtext = ''
  446.             self.tb.ScrollLines(-1)
  447.         
  448.  
  449.     
  450.     def log(self, str):
  451.         now = time.time()
  452.         t = time.localtime(now)
  453.         self.outstandingtext += '%d:%02d:%02d.%03d %s\r\n' % (t[3], t[4], t[5], int((now - int(now)) * 1000), str)
  454.  
  455.     
  456.     def logdata(self, str, data):
  457.         hd = ''
  458.         if data is not None:
  459.             hd = 'Data - ' + `len(data)` + ' bytes\n' + common.datatohexstring(data)
  460.         
  461.         self.log('%s %s' % (str, hd))
  462.  
  463.  
  464.  
  465. class GetPhoneDialog(wxDialog):
  466.     strings = ('PhoneBook', 'Calendar', 'Wallpaper', 'Ringtone')
  467.     NOTREQUESTED = 0
  468.     MERGE = 1
  469.     OVERWRITE = 2
  470.     HELPID = helpids.ID_GET_PHONE_DATA
  471.     
  472.     def __init__(self, frame, title, id = -1):
  473.         wxDialog.__init__(self, frame, id, title, style = wxCAPTION | wxSYSTEM_MENU | wxDEFAULT_DIALOG_STYLE)
  474.         gs = wxFlexGridSizer(6, 4, 5, 10)
  475.         gs.AddGrowableCol(1)
  476.         gs.AddMany([
  477.             (wxStaticText(self, -1, 'Get'), 0, wxEXPAND),
  478.             (wxStaticText(self, -1, 'Type'), 0, wxEXPAND),
  479.             (wxStaticText(self, -1, 'Add'), 0, wxEXPAND),
  480.             (wxStaticText(self, -1, 'Replace'), 0, wxEXPAND)])
  481.         self.cb = []
  482.         self.rb = []
  483.         for i in self.strings:
  484.             self.cb.append(wxCheckBox(self, -1, ''))
  485.             gs.Add(self.cb[-1], 0, wxEXPAND)
  486.             gs.Add(wxStaticText(self, -1, i), 0, wxEXPAND | wxALIGN_CENTER_VERTICAL)
  487.             self.rb.append([
  488.                 wxRadioButton(self, -1, '', style = wxRB_GROUP),
  489.                 wxRadioButton(self, -1, '')])
  490.             gs.Add(self.rb[-1][0], 0, wxEXPAND | wxALIGN_CENTRE)
  491.             gs.Add(self.rb[-1][1], 0, wxEXPAND | wxALIGN_CENTRE)
  492.             self.rb[-1][0].Enable(False)
  493.             self.rb[-1][0].SetValue(False)
  494.             self.rb[-1][1].SetValue(True)
  495.         
  496.         bs = wxBoxSizer(wxVERTICAL)
  497.         bs.Add(gs, 0, wxEXPAND | wxALL, 10)
  498.         bs.Add(wxStaticLine(self, -1), 0, wxEXPAND | wxTOP | wxBOTTOM, 7)
  499.         but = self.CreateButtonSizer(wxOK | wxCANCEL | wxHELP)
  500.         bs.Add(but, 0, wxEXPAND | wxALL, 10)
  501.         self.SetSizer(bs)
  502.         self.SetAutoLayout(True)
  503.         bs.Fit(self)
  504.         EVT_BUTTON(self, wxID_HELP, self.OnHelp)
  505.  
  506.     
  507.     def _setting(self, index):
  508.         if not self.cb[index].GetValue():
  509.             return self.NOTREQUESTED
  510.         
  511.         if self.rb[index][0].GetValue():
  512.             return self.MERGE
  513.         
  514.         return self.OVERWRITE
  515.  
  516.     
  517.     def GetPhoneBookSetting(self):
  518.         return self._setting(0)
  519.  
  520.     
  521.     def GetCalendarSetting(self):
  522.         return self._setting(1)
  523.  
  524.     
  525.     def GetWallpaperSetting(self):
  526.         return self._setting(2)
  527.  
  528.     
  529.     def GetRingtoneSetting(self):
  530.         return self._setting(3)
  531.  
  532.     
  533.     def OnHelp(self, _):
  534.         wxGetApp().displayhelpid(self.HELPID)
  535.  
  536.  
  537.  
  538. class SendPhoneDialog(GetPhoneDialog):
  539.     HELPID = helpids.ID_SEND_PHONE_DATA
  540.     
  541.     def __init__(self, frame, title, id = -1):
  542.         GetPhoneDialog.__init__(self, frame, title, id)
  543.         for i in self.cb:
  544.             i.SetValue(False)
  545.         
  546.         self.rb[2][0].Enable(True)
  547.         self.rb[3][0].Enable(True)
  548.  
  549.  
  550.  
  551. class ConfigDialog(wxDialog):
  552.     setme = '<setme>'
  553.     ID_DIRBROWSE = 1
  554.     ID_COMBROWSE = 2
  555.     ID_RETRY = 3
  556.     
  557.     def __init__(self, mainwindow, frame, title = 'BitPim Settings', id = -1):
  558.         wxDialog.__init__(self, frame, id, title, style = wxCAPTION | wxSYSTEM_MENU | wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
  559.         self.mw = mainwindow
  560.         gs = wxFlexGridSizer(2, 3, 5, 10)
  561.         gs.AddGrowableCol(1)
  562.         gs.Add(wxStaticText(self, -1, 'Disk storage'), 0, wxCENTER)
  563.         self.diskbox = wxTextCtrl(self, -1, self.setme, size = wxSize(400, 10))
  564.         gs.Add(self.diskbox, 0, wxEXPAND)
  565.         gs.Add(wxButton(self, self.ID_DIRBROWSE, 'Browse ...'), 0, wxEXPAND)
  566.         gs.Add(wxStaticText(self, -1, 'Com Port'), 0, wxCENTER)
  567.         self.commbox = wxTextCtrl(self, -1, self.setme)
  568.         gs.Add(self.commbox, 0, wxEXPAND)
  569.         gs.Add(wxButton(self, self.ID_COMBROWSE, 'Browse ...'), 0, wxEXPAND)
  570.         bs = wxBoxSizer(wxVERTICAL)
  571.         bs.Add(gs, 0, wxEXPAND | wxALL, 10)
  572.         bs.Add(wxStaticLine(self, -1), 0, wxEXPAND | wxTOP | wxBOTTOM, 7)
  573.         but = self.CreateButtonSizer(wxOK | wxCANCEL | wxHELP)
  574.         bs.Add(but, 0, wxCENTER, 10)
  575.         EVT_BUTTON(self, wxID_HELP, self.OnHelp)
  576.         EVT_BUTTON(self, self.ID_DIRBROWSE, self.OnDirBrowse)
  577.         EVT_BUTTON(self, self.ID_COMBROWSE, self.OnComBrowse)
  578.         EVT_BUTTON(self, wxID_OK, self.OnOK)
  579.         self.SetSizer(bs)
  580.         self.SetAutoLayout(True)
  581.         bs.Fit(self)
  582.  
  583.     
  584.     def OnOK(self, _):
  585.         dir = self.diskbox.GetValue()
  586.         
  587.         try:
  588.             os.makedirs(dir)
  589.         except:
  590.             pass
  591.  
  592.         if os.path.isdir(dir):
  593.             self.EndModal(wxID_OK)
  594.             return None
  595.         
  596.         wxTipWindow(self.diskbox, 'No such directory - please correct')
  597.  
  598.     
  599.     def OnHelp(self, _):
  600.         wxGetApp().displayhelpid(helpids.ID_SETTINGS_DIALOG)
  601.  
  602.     
  603.     def OnDirBrowse(self, _):
  604.         dlg = wxDirDialog(self, defaultPath = self.diskbox.GetValue(), style = wxDD_NEW_DIR_BUTTON)
  605.         res = dlg.ShowModal()
  606.         v = dlg.GetPath()
  607.         dlg.Destroy()
  608.         if res == wxID_OK:
  609.             self.diskbox.SetValue(v)
  610.         
  611.  
  612.     
  613.     def OnComBrowse(self, _):
  614.         self.mw.wt.clearcomm()
  615.         w = self.mw.config.ReadInt('combrowsewidth', 640)
  616.         h = self.mw.config.ReadInt('combrowseheight', 480)
  617.         p = self.mw.config.ReadInt('combrowsesash', 200)
  618.         dlg = CommPortDialog(self, defaultport = self.commbox.GetValue(), sashposition = p)
  619.         dlg.SetSize(wxSize(w, h))
  620.         dlg.Centre()
  621.         res = dlg.ShowModal()
  622.         v = dlg.GetPort()
  623.         sz = dlg.GetSize()
  624.         self.mw.config.WriteInt('combrowsewidth', sz.GetWidth())
  625.         self.mw.config.WriteInt('combrowseheight', sz.GetHeight())
  626.         self.mw.config.WriteInt('combrowsesash', dlg.sashposition)
  627.         dlg.Destroy()
  628.         if res == wxID_OK:
  629.             self.commbox.SetValue(v)
  630.         
  631.  
  632.     
  633.     def setfromconfig(self):
  634.         if len(self.mw.config.Read('path', '')):
  635.             self.diskbox.SetValue(self.mw.config.Read('path', ''))
  636.         
  637.         if len(self.mw.config.Read('lgvx4400port')):
  638.             self.commbox.SetValue(self.mw.config.Read('lgvx4400port', ''))
  639.         
  640.  
  641.     
  642.     def setdefaults(self):
  643.         if self.diskbox.GetValue() == self.setme:
  644.             if gui.IsMSWindows():
  645.                 import _winreg
  646.                 x = _winreg.ConnectRegistry(None, _winreg.HKEY_CURRENT_USER)
  647.                 y = _winreg.OpenKey(x, 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders')
  648.                 str = _winreg.QueryValueEx(y, 'Personal')[0]
  649.                 _winreg.CloseKey(y)
  650.                 _winreg.CloseKey(x)
  651.                 path = os.path.join(str, 'bitpim')
  652.             else:
  653.                 path = os.path.expanduser('~/.bitpim-files')
  654.             self.diskbox.SetValue(path)
  655.         
  656.         if self.commbox.GetValue() == self.setme:
  657.             comm = 'auto'
  658.             self.commbox.SetValue(comm)
  659.         
  660.  
  661.     
  662.     def updatevariables(self):
  663.         path = self.diskbox.GetValue()
  664.         self.mw.configpath = path
  665.         self.mw.ringerpath = self._fixup(os.path.join(path, 'ringer'))
  666.         self.mw.wallpaperpath = self._fixup(os.path.join(path, 'wallpaper'))
  667.         self.mw.phonebookpath = self._fixup(os.path.join(path, 'phonebook'))
  668.         self.mw.calendarpath = self._fixup(os.path.join(path, 'calendar'))
  669.         self.mw.config.Write('path', path)
  670.         self.mw.commportsetting = self.commbox.GetValue()
  671.         self.mw.config.Write('lgvx4400port', self.mw.commportsetting)
  672.         if self.mw.wt is not None:
  673.             self.mw.wt.clearcomm()
  674.         
  675.         commparm = { }
  676.         commparm['retryontimeout'] = self.mw.config.ReadInt('commretryontimeout', False)
  677.         commparm['timeout'] = self.mw.config.ReadInt('commtimeout', 3)
  678.         commparm['hardwareflow'] = self.mw.config.ReadInt('commhardwareflow', False)
  679.         commparm['softwareflow'] = self.mw.config.ReadInt('commsoftwareflow', False)
  680.         commparm['baud'] = self.mw.config.ReadInt('commbaud', 115200)
  681.         self.mw.commparams = commparm
  682.  
  683.     
  684.     def _fixup(self, path):
  685.         if len(path) >= 3:
  686.             if path[1] == ':' and path[2] == '\\' and path[3] == '\\':
  687.                 return path[0:2] + path[3:]
  688.             
  689.         
  690.         return path
  691.  
  692.     
  693.     def needconfig(self):
  694.         self.setfromconfig()
  695.         if self.diskbox.GetValue() == self.setme or self.commbox.GetValue() == self.setme:
  696.             self.setdefaults()
  697.             self.updatevariables()
  698.             if self.diskbox.GetValue() == self.setme or self.commbox.GetValue() == self.setme:
  699.                 return True
  700.             
  701.         
  702.         
  703.         try:
  704.             os.makedirs(self.diskbox.GetValue())
  705.         except:
  706.             pass
  707.  
  708.         if not os.path.isdir(self.diskbox.GetValue()):
  709.             return True
  710.         
  711.         return False
  712.  
  713.     
  714.     def ShowModal(self):
  715.         self.setfromconfig()
  716.         self.setdefaults()
  717.         ec = wxDialog.ShowModal(self)
  718.         if ec == wxID_OK:
  719.             self.updatevariables()
  720.         
  721.         return ec
  722.  
  723.  
  724.  
  725. class CommPortDialog(wxDialog):
  726.     ID_LISTBOX = 1
  727.     ID_TEXTBOX = 2
  728.     ID_REFRESH = 3
  729.     ID_SASH = 4
  730.     
  731.     def __init__(self, parent, id = -1, title = 'Choose a comm port', defaultport = 'auto', sashposition = 0):
  732.         wxDialog.__init__(self, parent, id, title, style = wxCAPTION | wxSYSTEM_MENU | wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
  733.         self.parent = parent
  734.         self.port = defaultport
  735.         self.sashposition = sashposition
  736.         p = self
  737.         splitter = wxSplitterWindow(p, self.ID_SASH, style = wxSP_3D | wxSP_LIVE_UPDATE)
  738.         self.lb = wxListBox(splitter, self.ID_LISTBOX, style = wxLB_SINGLE | wxLB_HSCROLL | wxLB_NEEDED_SB)
  739.         self.tb = wxHtmlWindow(splitter, self.ID_TEXTBOX, size = wxSize(400, 400))
  740.         splitter.SplitHorizontally(self.lb, self.tb, sashposition)
  741.         buttsizer = wxGridSizer(1, 4)
  742.         buttsizer.Add(wxButton(p, wxID_OK, 'OK'), 0, wxALL, 10)
  743.         buttsizer.Add(wxButton(p, self.ID_REFRESH, 'Refresh'), 0, wxALL, 10)
  744.         buttsizer.Add(wxButton(p, wxID_HELP, 'Help'), 0, wxALL, 10)
  745.         buttsizer.Add(wxButton(p, wxID_CANCEL, 'Cancel'), 0, wxALL, 10)
  746.         vbs = wxBoxSizer(wxVERTICAL)
  747.         vbs.Add(splitter, 1, wxEXPAND)
  748.         vbs.Add(buttsizer, 0, wxCENTER)
  749.         p.SetSizer(vbs)
  750.         p.SetAutoLayout(True)
  751.         vbs.Fit(p)
  752.         self.OnRefresh()
  753.         EVT_BUTTON(self, wxID_CANCEL, self.OnCancel)
  754.         EVT_BUTTON(self, wxID_HELP, self.OnHelp)
  755.         EVT_BUTTON(self, self.ID_REFRESH, self.OnRefresh)
  756.         EVT_BUTTON(self, wxID_OK, self.OnOk)
  757.         EVT_LISTBOX(self, self.ID_LISTBOX, self.OnListBox)
  758.         EVT_LISTBOX_DCLICK(self, self.ID_LISTBOX, self.OnListBox)
  759.         EVT_SPLITTER_SASH_POS_CHANGED(self, self.ID_SASH, self.OnSashChange)
  760.  
  761.     
  762.     def OnSashChange(self, _ = None):
  763.         self.sashposition = self.FindWindowById(self.ID_SASH).GetSashPosition()
  764.  
  765.     
  766.     def OnRefresh(self, _ = None):
  767.         self.tb.SetPage('<p><b>Refreshing</b> ...')
  768.         self.lb.Clear()
  769.         self.Update()
  770.         ports = comscan.comscan()
  771.         self.portinfo = comdiagnose.diagnose(ports)
  772.         if len(self.portinfo):
  773.             self.portinfo = [
  774.                 ('Automatic', 'auto', '<p>BitPim will try to detect the correct port automatically when accessing your phone')] + self.portinfo
  775.         
  776.         self.lb.Clear()
  777.         sel = -1
  778.         for name, actual, description in self.portinfo:
  779.             if sel < 0 and self.GetPort() == actual:
  780.                 sel = self.lb.GetCount()
  781.             
  782.             self.lb.Append(name)
  783.         
  784.         if sel < 0:
  785.             sel = 0
  786.         
  787.         if self.lb.GetCount():
  788.             self.lb.SetSelection(sel)
  789.             self.OnListBox()
  790.         else:
  791.             self.FindWindowById(wxID_OK).Enable(False)
  792.             self.tb.SetPage('<html><body>You do not have any com/serial ports on your system</body></html>')
  793.  
  794.     
  795.     def OnListBox(self, _ = None):
  796.         p = self.portinfo[self.lb.GetSelection()]
  797.         if p[1] is None:
  798.             self.FindWindowById(wxID_OK).Enable(False)
  799.         else:
  800.             self.port = p[1]
  801.             self.FindWindowById(wxID_OK).Enable(True)
  802.         self.tb.SetPage(p[2])
  803.  
  804.     
  805.     def OnCancel(self, _):
  806.         self.EndModal(wxID_CANCEL)
  807.  
  808.     
  809.     def OnOk(self, _):
  810.         self.EndModal(wxID_OK)
  811.  
  812.     
  813.     def OnHelp(self, _):
  814.         wxGetApp().displayhelpid(helpids.ID_COMMSETTINGS_DIALOG)
  815.  
  816.     
  817.     def GetPort(self):
  818.         return self.port
  819.  
  820.  
  821.  
  822. class MyFileDropTarget(wxFileDropTarget):
  823.     
  824.     def __init__(self, target):
  825.         wxFileDropTarget.__init__(self)
  826.         self.target = target
  827.  
  828.     
  829.     def OnDropFiles(self, x, y, filenames):
  830.         return self.target.OnDropFiles(x, y, filenames)
  831.  
  832.  
  833.  
  834. class FileView(wxListCtrl, wxListCtrlAutoWidthMixin):
  835.     skiplist = ('desktop.ini', 'thumbs.db', 'zbthumbnail.info')
  836.     
  837.     def __init__(self, mainwindow, parent, id = -1, style = wxLC_REPORT | wxLC_SINGLE_SEL):
  838.         wxListCtrl.__init__(self, parent, id, style = style)
  839.         wxListCtrlAutoWidthMixin.__init__(self)
  840.         self.droptarget = MyFileDropTarget(self)
  841.         self.SetDropTarget(self.droptarget)
  842.         self.mainwindow = mainwindow
  843.         self.thedir = None
  844.         self.wildcard = 'I forgot to set wildcard in derived class|*'
  845.         self.maxlen = 255
  846.         if style & wxLC_REPORT == wxLC_REPORT or gui.HasFullyFunctionalListView():
  847.             self.InsertColumn(0, 'Name')
  848.             self.InsertColumn(1, 'Bytes', wxLIST_FORMAT_RIGHT)
  849.             self.SetColumnWidth(0, 200)
  850.         
  851.         self.menu = wxMenu()
  852.         self.menu.Append(gui.ID_FV_OPEN, 'Open')
  853.         self.menu.AppendSeparator()
  854.         self.menu.Append(gui.ID_FV_DELETE, 'Delete')
  855.         self.menu.AppendSeparator()
  856.         self.menu.Append(gui.ID_FV_RENAME, 'Rename')
  857.         self.menu.Append(gui.ID_FV_REFRESH, 'Refresh')
  858.         self.menu.Append(gui.ID_FV_PROPERTIES, 'Properties')
  859.         self.addfilemenu = wxMenu()
  860.         self.addfilemenu.Append(gui.ID_FV_ADD, 'Add ...')
  861.         self.addfilemenu.Append(gui.ID_FV_REFRESH, 'Refresh')
  862.         EVT_MENU(self.menu, gui.ID_FV_REFRESH, self.OnRefresh)
  863.         EVT_MENU(self.addfilemenu, gui.ID_FV_REFRESH, self.OnRefresh)
  864.         EVT_MENU(self.addfilemenu, gui.ID_FV_ADD, self.OnAdd)
  865.         EVT_MENU(self.menu, gui.ID_FV_OPEN, self.OnLaunch)
  866.         EVT_MENU(self.menu, gui.ID_FV_DELETE, self.OnDelete)
  867.         EVT_MENU(self.menu, gui.ID_FV_PROPERTIES, self.OnProperties)
  868.         EVT_LEFT_DCLICK(self, self.OnLaunch)
  869.         EVT_LIST_ITEM_SELECTED(self, -1, self.OnItemActivated)
  870.         EVT_RIGHT_DOWN(self, self.OnRightDown)
  871.         EVT_COMMAND_RIGHT_CLICK(self, id, self.OnRightClick)
  872.         EVT_RIGHT_UP(self, self.OnRightClick)
  873.         EVT_KEY_DOWN(self, self.OnKeyDown)
  874.  
  875.     
  876.     def OnRightDown(self, event):
  877.         (item, flags) = self.HitTest(wxPoint(event.GetX(), event.GetY()))
  878.         if flags & wxLIST_HITTEST_ONITEM:
  879.             self.selecteditem = item
  880.             self.SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
  881.         else:
  882.             self.selecteditem = -1
  883.  
  884.     
  885.     def OnRightClick(self, event):
  886.         if self.selecteditem >= 0:
  887.             self.PopupMenu(self.menu, event.GetPosition())
  888.         else:
  889.             self.PopupMenu(self.addfilemenu, event.GetPosition())
  890.  
  891.     
  892.     def OnKeyDown(self, event):
  893.         if event.GetKeyCode() == WXK_DELETE:
  894.             self.OnDelete(event)
  895.             return None
  896.         
  897.         event.Skip()
  898.  
  899.     
  900.     def OnItemActivated(self, event):
  901.         self.selecteditem = event.m_itemIndex
  902.  
  903.     
  904.     def OnLaunch(self, _ = None):
  905.         name = self.GetItemText(self.selecteditem)
  906.         ext = name[name.rfind('.') + 1:]
  907.         type = wxTheMimeTypesManager.GetFileTypeFromExtension(ext)
  908.         cmd = type.GetOpenCommand(os.path.join(self.thedir, name))
  909.         if cmd is None or len(cmd) == 0:
  910.             dlg = AlertDialogWithHelp(self, "You don't have any programs defined to open ." + ext + ' files', 'Unable to open', (lambda _: wxGetApp().displayhelpid(helpids.ID_NO_MIME_OPEN)), style = wxOK | wxICON_INFORMATION)
  911.             dlg.ShowModal()
  912.             dlg.Destroy()
  913.         else:
  914.             
  915.             try:
  916.                 wxExecute(cmd)
  917.             except:
  918.                 dlg = AlertDialogWithHelp(self, "Unable to execute '" + cmd + "'", 'Open failed', (lambda _: wxGetApp().displayhelpid(helpids.ID_MIME_EXEC_FAILED)), style = wxOK | wxICON_ERROR)
  919.                 dlg.ShowModal()
  920.                 dlg.Destroy()
  921.  
  922.  
  923.     
  924.     def OnDropFiles(self, _, dummy, filenames):
  925.         target = self
  926.         t = self.mainwindow.nb.GetPage(self.mainwindow.nb.GetSelection())
  927.         if isinstance(t, FileView):
  928.             target = t
  929.         
  930.         for f in filenames:
  931.             target.OnAddFile(f)
  932.         
  933.  
  934.     
  935.     def OnAdd(self, _ = None):
  936.         dlg = wxFileDialog(self, 'Choose files', style = wxOPEN | wxMULTIPLE, wildcard = self.wildcard)
  937.         if dlg.ShowModal() == wxID_OK:
  938.             for file in dlg.GetPaths():
  939.                 self.OnAddFile(file)
  940.             
  941.         
  942.         dlg.Destroy()
  943.  
  944.     
  945.     def OnAddFile(self, _):
  946.         raise Exception('not implemented')
  947.  
  948.     
  949.     def OnRefresh(self, _ = None):
  950.         result = { }
  951.         self.getfromfs(result)
  952.         self.populate(result)
  953.  
  954.     
  955.     def OnDelete(self, _):
  956.         name = self.GetItemText(self.selecteditem)
  957.         os.remove(os.path.join(self.thedir, name))
  958.         self.OnRefresh()
  959.  
  960.     
  961.     def versionupgrade(self, dict, version):
  962.         raise Exception('not implemented')
  963.  
  964.     
  965.     def OnProperties(self, _):
  966.         raise Exception('not implemented')
  967.  
  968.     
  969.     def getfromfs(self, _):
  970.         raise Exception('not implemented')
  971.  
  972.     
  973.     def populate(self, _):
  974.         raise Exception('not implemented')
  975.  
  976.     
  977.     def seticonview(self):
  978.         self.SetSingleStyle(wxLC_REPORT, False)
  979.         self.SetSingleStyle(wxLC_ICON, True)
  980.  
  981.     
  982.     def setlistview(self):
  983.         self.SetSingleStyle(wxLC_ICON, False)
  984.         self.SetSingleStyle(wxLC_REPORT, True)
  985.  
  986.     
  987.     def genericpopulatefs(self, dict, key, indexkey, version):
  988.         
  989.         try:
  990.             os.makedirs(self.thedir)
  991.         except:
  992.             pass
  993.  
  994.         if not os.path.isdir(self.thedir):
  995.             raise Exception('Bad directory for ' + key + " '" + self.thedir + "'")
  996.         
  997.         for f in os.listdir(self.thedir):
  998.             if f.lower() not in self.skiplist:
  999.                 os.remove(os.path.join(self.thedir, f))
  1000.                 continue
  1001.         
  1002.         d = dict[key]
  1003.         for i in d:
  1004.             f = open(os.path.join(self.thedir, i), 'wb')
  1005.             f.write(d[i])
  1006.             f.close()
  1007.         
  1008.         d = { }
  1009.         d[indexkey] = dict[indexkey]
  1010.         common.writeversionindexfile(os.path.join(self.thedir, 'index.idx'), d, version)
  1011.         return dict
  1012.  
  1013.     
  1014.     def genericgetfromfs(self, result, key, indexkey, currentversion):
  1015.         
  1016.         try:
  1017.             os.makedirs(self.thedir)
  1018.         except:
  1019.             pass
  1020.  
  1021.         if not os.path.isdir(self.thedir):
  1022.             raise Exception('Bad directory for ' + key + " '" + self.thedir + "'")
  1023.         
  1024.         dict = { }
  1025.         for file in os.listdir(self.thedir):
  1026.             if file == 'index.idx':
  1027.                 d = { }
  1028.                 d['result'] = { }
  1029.                 common.readversionedindexfile(os.path.join(self.thedir, file), d, self.versionupgrade, currentversion)
  1030.                 result.update(d['result'])
  1031.                 continue
  1032.             if file.lower() in self.skiplist:
  1033.                 continue
  1034.                 continue
  1035.             f = open(os.path.join(self.thedir, file), 'rb')
  1036.             data = f.read()
  1037.             f.close()
  1038.             dict[file] = data
  1039.         
  1040.         result[key] = dict
  1041.         if indexkey not in result:
  1042.             result[indexkey] = { }
  1043.         
  1044.         return result
  1045.  
  1046.     
  1047.     def getshortenedbasename(self, filename, newext = ''):
  1048.         filename = basename(filename).lower()
  1049.         if len(newext):
  1050.             filename = stripext(filename) + '.' + newext
  1051.         
  1052.         if len(filename) > self.maxlen:
  1053.             chop = len(filename) - self.maxlen
  1054.             filename = stripext(filename)[:-chop] + '.' + getext(filename)
  1055.         
  1056.         return os.path.join(self.thedir, filename)
  1057.  
  1058.  
  1059.  
  1060. class RingerView(FileView):
  1061.     CURRENTFILEVERSION = 1
  1062.     
  1063.     def __init__(self, mainwindow, parent, id = -1):
  1064.         FileView.__init__(self, mainwindow, parent, id)
  1065.         self.InsertColumn(2, 'Length')
  1066.         self.InsertColumn(3, 'Index')
  1067.         self.InsertColumn(4, 'Description')
  1068.         il = wxImageList(32, 32)
  1069.         il.Add(gui.getbitmap('ringer'))
  1070.         self.AssignImageList(il, wxIMAGE_LIST_NORMAL)
  1071.         self._data = { }
  1072.         self._data['ringtone'] = { }
  1073.         self._data['ringtone-index'] = { }
  1074.         self.wildcard = 'MIDI files (*.mid)|*.mid'
  1075.         self.maxlen = 19
  1076.  
  1077.     
  1078.     def getdata(self, dict):
  1079.         dict.update(self._data)
  1080.         return dict
  1081.  
  1082.     
  1083.     def OnAddFile(self, file):
  1084.         self.thedir = self.mainwindow.ringerpath
  1085.         target = self.getshortenedbasename(file, 'mid')
  1086.         if target == None:
  1087.             return None
  1088.         
  1089.         f = open(file, 'rb')
  1090.         contents = f.read()
  1091.         f.close()
  1092.         if len(contents) >= 65534:
  1093.             raise Exception(file + ' is too big at ' + `len(contents)` + ' bytes.  Max size is 64k')
  1094.         
  1095.         f = open(target, 'wb')
  1096.         f.write(contents)
  1097.         f.close()
  1098.         self.OnRefresh()
  1099.  
  1100.     
  1101.     def populatefs(self, dict):
  1102.         self.thedir = self.mainwindow.ringerpath
  1103.         return self.genericpopulatefs(dict, 'ringtone', 'ringtone-index', self.CURRENTFILEVERSION)
  1104.  
  1105.     
  1106.     def populate(self, dict):
  1107.         self.DeleteAllItems()
  1108.         self._data = { }
  1109.         self._data['ringtone'] = dict['ringtone'].copy()
  1110.         self._data['ringtone-index'] = dict['ringtone-index'].copy()
  1111.         count = 0
  1112.         keys = dict['ringtone'].keys()
  1113.         keys.sort()
  1114.         for i in keys:
  1115.             item = { }
  1116.             item['name'] = i
  1117.             item['data'] = dict['ringtone'][i]
  1118.             item['index'] = -1
  1119.             for ii in dict['ringtone-index']:
  1120.                 if dict['ringtone-index'][ii] == i:
  1121.                     item['index'] = ii
  1122.                     break
  1123.                     continue
  1124.             
  1125.             self.InsertImageStringItem(count, item['name'], 0)
  1126.             self.SetStringItem(count, 0, item['name'])
  1127.             self.SetStringItem(count, 1, `len(item['data'])`)
  1128.             self.SetStringItem(count, 2, '1 second :-)')
  1129.             self.SetStringItem(count, 3, `item['index']`)
  1130.             self.SetStringItem(count, 4, 'Midi file')
  1131.             count += 1
  1132.         
  1133.  
  1134.     
  1135.     def getfromfs(self, result):
  1136.         self.thedir = self.mainwindow.ringerpath
  1137.         return self.genericgetfromfs(result, 'ringtone', 'ringtone-index', self.CURRENTFILEVERSION)
  1138.  
  1139.     
  1140.     def versionupgrade(self, dict, version):
  1141.         if version == 0:
  1142.             version = 1
  1143.         
  1144.  
  1145.  
  1146.  
  1147. class WallpaperView(FileView):
  1148.     CURRENTFILEVERSION = 1
  1149.     ID_DELETEFILE = 2
  1150.     ID_IGNOREFILE = 3
  1151.     
  1152.     def __init__(self, mainwindow, parent, id = -1):
  1153.         FileView.__init__(self, mainwindow, parent, id, style = wxLC_ICON | wxLC_SINGLE_SEL)
  1154.         if gui.HasFullyFunctionalListView():
  1155.             self.InsertColumn(2, 'Size')
  1156.             self.InsertColumn(3, 'Index')
  1157.         
  1158.         self._data = { }
  1159.         self._data['wallpaper'] = { }
  1160.         self._data['wallpaper-index'] = { }
  1161.         self.maxlen = 19
  1162.         self.wildcard = 'Image files|*.bmp;*.jpg;*.jpeg;*.png;*.gif;*.pnm;*.tiff;*.ico;*.bci'
  1163.         self.usewidth = 120
  1164.         self.useheight = 98
  1165.         self.addfilemenu.Insert(1, gui.ID_FV_PASTE, 'Paste')
  1166.         EVT_MENU(self.addfilemenu, gui.ID_FV_PASTE, self.OnPaste)
  1167.  
  1168.     
  1169.     def isBCI(self, filename):
  1170.         f = open(filename, 'rb')
  1171.         four = f.read(4)
  1172.         f.close()
  1173.         if four == 'BCI\x00':
  1174.             return True
  1175.         
  1176.         return False
  1177.  
  1178.     
  1179.     def getdata(self, dict):
  1180.         dict.update(self._data)
  1181.         return dict
  1182.  
  1183.     
  1184.     def populate(self, dict):
  1185.         self.DeleteAllItems()
  1186.         self._data = { }
  1187.         self._data['wallpaper'] = dict['wallpaper'].copy()
  1188.         self._data['wallpaper-index'] = dict['wallpaper-index'].copy()
  1189.         il = wxImageList(self.usewidth, self.useheight)
  1190.         self.AssignImageList(il, wxIMAGE_LIST_NORMAL)
  1191.         count = 0
  1192.         keys = dict['wallpaper'].keys()
  1193.         keys.sort()
  1194.         for i in keys:
  1195.             file = os.path.join(self.mainwindow.wallpaperpath, i)
  1196.             if self.isBCI(file):
  1197.                 image = brewcompressedimage.getimage(file)
  1198.             else:
  1199.                 image = wxImage(file)
  1200.             if not image.Ok():
  1201.                 dlg = AnotherDialog(self, 'This is not a valid image file:\n\n' + file, 'Invalid Image file', (('Delete', self.ID_DELETEFILE), ('Ignore', self.ID_IGNOREFILE), ('Help', wxID_HELP)), (lambda _: wxGetApp().displayhelpid(helpids.ID_INVALID_FILE_MESSAGE)))
  1202.                 x = dlg.ShowModal()
  1203.                 dlg.Destroy()
  1204.                 print 'result is', x
  1205.                 if x == self.ID_DELETEFILE:
  1206.                     os.remove(file)
  1207.                     continue
  1208.                 continue
  1209.             
  1210.             width = min(image.GetWidth(), self.usewidth)
  1211.             height = min(image.GetHeight(), self.useheight)
  1212.             img = image.GetSubImage(wxRect(0, 0, width, height))
  1213.             if width != self.usewidth or height != self.useheight:
  1214.                 b = wxEmptyBitmap(self.usewidth, self.useheight)
  1215.                 mdc = wxMemoryDC()
  1216.                 mdc.SelectObject(b)
  1217.                 mdc.Clear()
  1218.                 mdc.DrawBitmap(img.ConvertToBitmap(), 0, 0, True)
  1219.                 mdc.SelectObject(wxNullBitmap)
  1220.                 bitmap = b
  1221.             else:
  1222.                 bitmap = img.ConvertToBitmap()
  1223.             pos = -1
  1224.             
  1225.             try:
  1226.                 pos = il.Add(bitmap)
  1227.             except:
  1228.                 pass
  1229.  
  1230.             if pos < 0:
  1231.                 dlg = wxMessageDialog(self, "Failed to add to imagelist image in '" + file + "'", 'Imagelist got upset', style = wxOK | wxICON_ERROR)
  1232.                 dlg.ShowModal()
  1233.                 il.Add(wxNullBitmap)
  1234.             
  1235.             item = { }
  1236.             item['name'] = i
  1237.             item['data'] = dict['wallpaper'][i]
  1238.             item['index'] = -1
  1239.             for ii in dict['wallpaper-index']:
  1240.                 if dict['wallpaper-index'][ii] == i:
  1241.                     item['index'] = ii
  1242.                     break
  1243.                     continue
  1244.             
  1245.             self.InsertImageStringItem(count, item['name'], count)
  1246.             if gui.HasFullyFunctionalListView():
  1247.                 self.SetStringItem(count, 0, item['name'])
  1248.                 self.SetStringItem(count, 1, `len(item['data'])`)
  1249.                 self.SetStringItem(count, 2, '%d x %d' % (image.GetWidth(), image.GetHeight()))
  1250.                 self.SetStringItem(count, 3, `item['index']`)
  1251.             
  1252.             image.Destroy()
  1253.             count += 1
  1254.         
  1255.  
  1256.     
  1257.     def OnPaste(self, _ = None):
  1258.         do = wxBitmapDataObject()
  1259.         wxTheClipboard.Open()
  1260.         success = wxTheClipboard.GetData(do)
  1261.         wxTheClipboard.Close()
  1262.         if not success:
  1263.             wxMessageBox("There isn't an image in the clipboard", 'Error')
  1264.             return None
  1265.         
  1266.         self.thedir = self.mainwindow.wallpaperpath
  1267.         for i in range(255):
  1268.             name = 'clipboard' + `i` + '.bmp'
  1269.             if not os.path.exists(os.path.join(self.thedir, name)):
  1270.                 break
  1271.                 continue
  1272.         
  1273.         self.OnAddImage(wxImageFromBitmap(do.GetBitmap()), name)
  1274.  
  1275.     
  1276.     def OnAddFile(self, file):
  1277.         self.thedir = self.mainwindow.wallpaperpath
  1278.         if self.isBCI(file):
  1279.             target = os.path.join(self.thedir, os.path.basename(file))
  1280.             src = open(file, 'rb')
  1281.             dest = open(target, 'wb')
  1282.             dest.write(src.read())
  1283.             dest.close()
  1284.             src.close()
  1285.             self.OnRefresh()
  1286.             return None
  1287.         
  1288.         img = wxImage(file)
  1289.         if not img.Ok():
  1290.             dlg = wxMessageDialog(self, "Failed to understand the image in '" + file + "'", 'Image not understood', style = wxOK | wxICON_ERROR)
  1291.             dlg.ShowModal()
  1292.             return None
  1293.         
  1294.         self.OnAddImage(img, file)
  1295.  
  1296.     
  1297.     def OnAddImage(self, img, file):
  1298.         target = self.getshortenedbasename(file, 'bmp')
  1299.         if target == None:
  1300.             return None
  1301.         
  1302.         obj = img
  1303.         if img.GetWidth() > self.usewidth * 120 / 100 and img.GetHeight() > self.useheight * 120 / 100 and img.GetWidth() < self.usewidth * 60 / 100 or img.GetHeight() < self.useheight * 60 / 100:
  1304.             bitmap = wxEmptyBitmap(self.usewidth, self.useheight)
  1305.             mdc = wxMemoryDC()
  1306.             mdc.SelectObject(bitmap)
  1307.             sfactorw = self.usewidth * 10000 / img.GetWidth()
  1308.             sfactorh = self.useheight * 10000 / img.GetHeight()
  1309.             sfactor = min(sfactorw, sfactorh)
  1310.             newwidth = img.GetWidth() * sfactor / 10000
  1311.             newheight = img.GetHeight() * sfactor / 10000
  1312.             self.mainwindow.OnLog('Resizing %s from %dx%d to %dx%d' % (target, img.GetWidth(), img.GetHeight(), newwidth, newheight))
  1313.             img.Rescale(newwidth, newheight)
  1314.             posx = self.usewidth - (self.usewidth + newwidth) / 2
  1315.             posy = self.useheight - (self.useheight + newheight) / 2
  1316.             mdc.Clear()
  1317.             mdc.DrawBitmap(img.ConvertToBitmap(), posx, posy, True)
  1318.             obj = bitmap
  1319.         
  1320.         if not obj.SaveFile(target, wxBITMAP_TYPE_BMP):
  1321.             os.remove(target)
  1322.             dlg = wxMessageDialog(self, "Failed to convert the image in '" + file + "'", 'Image not converted', style = wxOK | wxICON_ERROR)
  1323.             dlg.ShowModal()
  1324.             return None
  1325.         
  1326.         self.OnRefresh()
  1327.  
  1328.     
  1329.     def populatefs(self, dict):
  1330.         self.thedir = self.mainwindow.wallpaperpath
  1331.         return self.genericpopulatefs(dict, 'wallpaper', 'wallpaper-index', self.CURRENTFILEVERSION)
  1332.  
  1333.     
  1334.     def getfromfs(self, result):
  1335.         self.thedir = self.mainwindow.wallpaperpath
  1336.         return self.genericgetfromfs(result, 'wallpaper', 'wallpaper-index', self.CURRENTFILEVERSION)
  1337.  
  1338.     
  1339.     def versionupgrade(self, dict, version):
  1340.         if version == 0:
  1341.             version = 1
  1342.         
  1343.  
  1344.  
  1345.  
  1346. def basename(name):
  1347.     if name.rfind('\\') >= 0 or name.rfind('/') >= 0:
  1348.         pos = max(name.rfind('\\'), name.rfind('/'))
  1349.         name = name[pos + 1:]
  1350.     
  1351.     return name
  1352.  
  1353.  
  1354. def stripext(name):
  1355.     if name.rfind('.') >= 0:
  1356.         name = name[:name.rfind('.')]
  1357.     
  1358.     return name
  1359.  
  1360.  
  1361. def getext(name):
  1362.     if name.rfind('.') >= 0:
  1363.         return name[name.rfind('.') + 1:]
  1364.     
  1365.     return ''
  1366.  
  1367.  
  1368. class Calendar(calendarcontrol.Calendar):
  1369.     CURRENTFILEVERSION = 2
  1370.     
  1371.     def __init__(self, mainwindow, parent, id = -1):
  1372.         self.mainwindow = mainwindow
  1373.         self.entrycache = { }
  1374.         self.entries = { }
  1375.         self.repeating = []
  1376.         self._data = { }
  1377.         calendarcontrol.Calendar.__init__(self, parent, rows = 5, id = id)
  1378.         self.dialog = DayViewDialog(self, self)
  1379.         self._nextpos = -1
  1380.  
  1381.     
  1382.     def getdata(self, dict):
  1383.         dict['calendar'] = self._data
  1384.         return dict
  1385.  
  1386.     
  1387.     def updateonchange(self):
  1388.         d = { }
  1389.         d = self.getdata(d)
  1390.         self.populatefs(d)
  1391.         self.populate(d)
  1392.         self.RefreshAllEntries()
  1393.  
  1394.     
  1395.     def AddEntry(self, entry):
  1396.         self._data[entry['pos']] = entry
  1397.         self.updateonchange()
  1398.  
  1399.     
  1400.     def DeleteEntry(self, entry):
  1401.         del self._data[entry['pos']]
  1402.         self.updateonchange()
  1403.  
  1404.     
  1405.     def DeleteEntryRepeat(self, entry, year, month, day):
  1406.         e = self._data[entry['pos']]
  1407.         if not e.has_key('exceptions'):
  1408.             e['exceptions'] = []
  1409.         
  1410.         e['exceptions'].append((year, month, day))
  1411.         self.updateonchange()
  1412.  
  1413.     
  1414.     def ChangeEntry(self, oldentry, newentry):
  1415.         self._data[newentry['pos']] = newentry
  1416.         self.updateonchange()
  1417.  
  1418.     
  1419.     def getentrydata(self, year, month, day):
  1420.         res = self.entrycache.get((year, month, day), None)
  1421.         if res is not None:
  1422.             return res
  1423.         
  1424.         dayofweek = calendar.weekday(year, month, day)
  1425.         dayofweek = (dayofweek + 1) % 7
  1426.         res = []
  1427.         fixed = self.entries.get((year, month, day), [])
  1428.         res.extend(fixed)
  1429.         repeats = []
  1430.         for i in self.repeating:
  1431.             (y, m, d) = i['start'][0:3]
  1432.             if not year < y:
  1433.                 if year <= y and month < m and year <= y and month <= m and day < d:
  1434.                     continue
  1435.                 
  1436.             (y, m, d) = i['end'][0:3]
  1437.             if not year > y:
  1438.                 if year == y and month > m and year == y and month == m and day > d:
  1439.                     continue
  1440.                 
  1441.             if (year, month, day) in i.get('exceptions', ()):
  1442.                 continue
  1443.             
  1444.             repeating = i['repeat']
  1445.             if repeating == 'daily':
  1446.                 repeats.append(i)
  1447.                 continue
  1448.             
  1449.             if repeating == 'monfri':
  1450.                 if dayofweek > 0 and dayofweek < 6:
  1451.                     repeats.append(i)
  1452.                     continue
  1453.                 continue
  1454.             
  1455.             if repeating == 'weekly':
  1456.                 if i['dayofweek'] == dayofweek:
  1457.                     repeats.append(i)
  1458.                     continue
  1459.                 continue
  1460.             
  1461.             if repeating == 'monthly':
  1462.                 if day == i['start'][2]:
  1463.                     repeats.append(i)
  1464.                     continue
  1465.                 continue
  1466.             
  1467.             if repeating == 'yearly':
  1468.                 if day == i['start'][2] and month == i['start'][1]:
  1469.                     repeats.append(i)
  1470.                     continue
  1471.                 continue
  1472.                 continue
  1473.         
  1474.         res.extend(repeats)
  1475.         self.entrycache[(year, month, day)] = res
  1476.         return res
  1477.  
  1478.     
  1479.     def newentryfactory(self, year, month, day):
  1480.         res = { }
  1481.         now = time.localtime()
  1482.         res['start'] = (year, month, day, now.tm_hour, now.tm_min)
  1483.         res['end'] = [
  1484.             year,
  1485.             month,
  1486.             day,
  1487.             now.tm_hour,
  1488.             now.tm_min]
  1489.         if res['end'][3] < 23:
  1490.             res['end'][3] += 1
  1491.             res['end'][4] = 0
  1492.         else:
  1493.             res['end'][3] = 23
  1494.             res['end'][4] = 59
  1495.         res['repeat'] = None
  1496.         res['description'] = 'New event'
  1497.         res['changeserial'] = 1
  1498.         res['snoozedelay'] = 0
  1499.         res['alarm'] = None
  1500.         res['daybitmap'] = 0
  1501.         res['ringtone'] = 0
  1502.         res['pos'] = self.allocnextpos()
  1503.         return res
  1504.  
  1505.     
  1506.     def getdaybitmap(self, start, repeat):
  1507.         if repeat != 'weekly':
  1508.             return 0
  1509.         
  1510.         dayofweek = calendar.weekday(*start[:3])
  1511.         dayofweek = (dayofweek + 1) % 7
  1512.         return [
  1513.             2048,
  1514.             1024,
  1515.             512,
  1516.             256,
  1517.             128,
  1518.             64,
  1519.             32][dayofweek]
  1520.  
  1521.     
  1522.     def allocnextpos(self):
  1523.         while True:
  1524.             (self._nextpos, res) = (self._nextpos - 1, self._nextpos)
  1525.             if res not in self._data:
  1526.                 return res
  1527.                 continue
  1528.         return -1
  1529.  
  1530.     
  1531.     def OnGetEntries(self, year, month, day):
  1532.         res = [ (i['start'][3], i['start'][4], i['description']) for i in self.getentrydata(year, month, day) ]
  1533.         res.sort()
  1534.         return res
  1535.  
  1536.     
  1537.     def OnEdit(self, year, month, day):
  1538.         if self.dialog.dirty:
  1539.             wxBell()
  1540.         else:
  1541.             self.dialog.setdate(year, month, day)
  1542.             self.dialog.Show(True)
  1543.  
  1544.     
  1545.     def populate(self, dict):
  1546.         self._data = dict['calendar']
  1547.         self.entrycache = { }
  1548.         self.entries = { }
  1549.         self.repeating = []
  1550.         for entry in self._data:
  1551.             entry = self._data[entry]
  1552.             (y, m, d, h, min) = entry['start']
  1553.             if entry['repeat'] is None:
  1554.                 if not self.entries.has_key((y, m, d)):
  1555.                     self.entries[(y, m, d)] = []
  1556.                 
  1557.                 self.entries[(y, m, d)].append(entry)
  1558.                 continue
  1559.             
  1560.             if entry['repeat'] == 'weekly':
  1561.                 entry['dayofweek'] = (calendar.weekday(y, m, d) + 1) % 7
  1562.             
  1563.             self.repeating.append(entry)
  1564.         
  1565.         self.RefreshAllEntries()
  1566.  
  1567.     
  1568.     def populatefs(self, dict):
  1569.         self.thedir = self.mainwindow.calendarpath
  1570.         
  1571.         try:
  1572.             os.makedirs(self.thedir)
  1573.         except:
  1574.             pass
  1575.  
  1576.         if not os.path.isdir(self.thedir):
  1577.             raise Exception("Bad directory for calendar '" + self.thedir + "'")
  1578.         
  1579.         for f in os.listdir(self.thedir):
  1580.             os.remove(os.path.join(self.thedir, f))
  1581.         
  1582.         d = { }
  1583.         d['calendar'] = dict['calendar']
  1584.         common.writeversionindexfile(os.path.join(self.thedir, 'index.idx'), d, self.CURRENTFILEVERSION)
  1585.         return dict
  1586.  
  1587.     
  1588.     def getfromfs(self, dict):
  1589.         self.thedir = self.mainwindow.calendarpath
  1590.         
  1591.         try:
  1592.             os.makedirs(self.thedir)
  1593.         except:
  1594.             pass
  1595.  
  1596.         if not os.path.isdir(self.thedir):
  1597.             raise Exception("Bad directory for calendar '" + self.thedir + "'")
  1598.         
  1599.         if os.path.exists(os.path.join(self.thedir, 'index.idx')):
  1600.             d = {
  1601.                 'result': { } }
  1602.             common.readversionedindexfile(os.path.join(self.thedir, 'index.idx'), d, self.versionupgrade, self.CURRENTFILEVERSION)
  1603.             dict.update(d['result'])
  1604.         else:
  1605.             dict['calendar'] = { }
  1606.         return dict
  1607.  
  1608.     
  1609.     def versionupgrade(self, dict, version):
  1610.         if version == 0:
  1611.             version = 1
  1612.         
  1613.         if version == 1:
  1614.             version = 2
  1615.             for k in dict['result']['calendar']:
  1616.                 entry = dict['result']['calendar'][k]
  1617.                 entry['daybitmap'] = self.getdaybitmap(entry['start'], entry['repeat'])
  1618.                 del entry['?d']
  1619.             
  1620.         
  1621.  
  1622.  
  1623.  
  1624. class DayViewDialog(wxDialog):
  1625.     ID_PREV = 1
  1626.     ID_NEXT = 2
  1627.     ID_ADD = 3
  1628.     ID_DELETE = 4
  1629.     ID_CLOSE = 5
  1630.     ID_LISTBOX = 6
  1631.     ID_START = 7
  1632.     ID_END = 8
  1633.     ID_REPEAT = 9
  1634.     ID_DESCRIPTION = 10
  1635.     ID_SAVE = 11
  1636.     ID_HELP = 12
  1637.     ID_REVERT = 13
  1638.     ANSWER_ORIGINAL = 1
  1639.     ANSWER_THIS = 2
  1640.     ANSWER_CANCEL = 3
  1641.     
  1642.     def __init__(self, parent, calendarwidget, id = -1, title = 'Edit Calendar'):
  1643.         self.cw = calendarwidget
  1644.         wxDialog.__init__(self, parent, id, title, style = wxDEFAULT_DIALOG_STYLE)
  1645.         vbs = wxBoxSizer(wxVERTICAL)
  1646.         prev = wxButton(self, self.ID_PREV, '<', style = wxBU_EXACTFIT)
  1647.         next = wxButton(self, self.ID_NEXT, '>', style = wxBU_EXACTFIT)
  1648.         self.title = wxStaticText(self, -1, 'Date here', style = wxALIGN_CENTRE | wxST_NO_AUTORESIZE)
  1649.         hbs1 = wxBoxSizer(wxHORIZONTAL)
  1650.         hbs1.Add(prev, 0, wxEXPAND)
  1651.         hbs1.Add(self.title, 1, wxEXPAND)
  1652.         hbs1.Add(next, 0, wxEXPAND)
  1653.         vbs.Add(hbs1, 0, wxEXPAND)
  1654.         self.listbox = wxListBox(self, self.ID_LISTBOX, style = wxLB_SINGLE | wxLB_HSCROLL | wxLB_NEEDED_SB)
  1655.         add = wxButton(self, self.ID_ADD, 'New')
  1656.         hbs2 = wxBoxSizer(wxHORIZONTAL)
  1657.         hbs2.Add(add, 1, wxALIGN_CENTER | wxLEFT | wxRIGHT, border = 5)
  1658.         lbs = wxBoxSizer(wxVERTICAL)
  1659.         lbs.Add(self.listbox, 1, wxEXPAND | wxBOTTOM, border = 5)
  1660.         lbs.Add(hbs2, 0, wxEXPAND)
  1661.         self.fieldnames = ('description', 'start', 'end', 'repeat', 'alarm', 'ringtone', 'changeserial', 'snoozedelay')
  1662.         self.fielddesc = ('Description', 'Start', 'End', 'Repeat', 'Alarm', 'Ringtone', 'changeserial', 'Snooze Delay')
  1663.         gs = wxFlexGridSizer(-1, 2, 5, 5)
  1664.         gs.AddGrowableCol(1)
  1665.         self.fields = { }
  1666.         for desc, field in zip(self.fielddesc, self.fieldnames):
  1667.             t = wxStaticText(self, -1, desc, style = wxALIGN_LEFT)
  1668.             gs.Add(t)
  1669.             if field == 'start':
  1670.                 c = DVDateTimeControl(self, self.ID_START)
  1671.             elif field == 'end':
  1672.                 c = DVDateTimeControl(self, self.ID_END)
  1673.             elif field == 'repeat':
  1674.                 c = DVRepeatControl(self, self.ID_REPEAT)
  1675.             elif field == 'description':
  1676.                 c = DVTextControl(self, self.ID_DESCRIPTION, 'dummy')
  1677.             else:
  1678.                 print 'field', field, 'needs an id'
  1679.                 c = DVIntControl(self, -1)
  1680.             gs.Add(c, 0, wxEXPAND)
  1681.             self.fields[field] = c
  1682.         
  1683.         delete = wxButton(self, self.ID_DELETE, 'Delete')
  1684.         revert = wxButton(self, self.ID_REVERT, 'Revert')
  1685.         save = wxButton(self, self.ID_SAVE, 'Save')
  1686.         hbs4 = wxBoxSizer(wxHORIZONTAL)
  1687.         hbs4.Add(delete, 1, wxALIGN_CENTRE | wxLEFT, border = 10)
  1688.         hbs4.Add(revert, 1, wxALIGN_CENTRE | wxLEFT | wxRIGHT, border = 10)
  1689.         hbs4.Add(save, 1, wxALIGN_CENTRE | wxRIGHT, border = 10)
  1690.         vbs2 = wxBoxSizer(wxVERTICAL)
  1691.         vbs2.Add(gs, 1, wxEXPAND | wxBOTTOM, border = 5)
  1692.         vbs2.Add(hbs4, 0, wxEXPAND | wxALIGN_CENTRE)
  1693.         hbs3 = wxBoxSizer(wxHORIZONTAL)
  1694.         hbs3.Add(lbs, 1, wxEXPAND | wxALL, 5)
  1695.         hbs3.Add(vbs2, 2, wxEXPAND | wxALL, 5)
  1696.         vbs.Add(hbs3, 1, wxEXPAND)
  1697.         vbs.Add(wxStaticLine(self, -1, style = wxLI_HORIZONTAL), 0, wxEXPAND)
  1698.         help = wxButton(self, self.ID_HELP, 'Help')
  1699.         close = wxButton(self, self.ID_CLOSE, 'Close')
  1700.         hbs4 = wxBoxSizer(wxHORIZONTAL)
  1701.         hbs4.Add(help, 0, wxALL, 5)
  1702.         hbs4.Add(close, 0, wxALL, 5)
  1703.         vbs.Add(hbs4, 0, wxALIGN_RIGHT | wxALL, 5)
  1704.         self.SetSizer(vbs)
  1705.         self.SetAutoLayout(True)
  1706.         vbs.Fit(self)
  1707.         self.FindWindowById(self.ID_DELETE).Enable(False)
  1708.         EVT_LISTBOX(self, self.ID_LISTBOX, self.OnListBoxItem)
  1709.         EVT_LISTBOX_DCLICK(self, self.ID_LISTBOX, self.OnListBoxItem)
  1710.         EVT_BUTTON(self, self.ID_SAVE, self.OnSaveButton)
  1711.         EVT_BUTTON(self, self.ID_REVERT, self.OnRevertButton)
  1712.         EVT_BUTTON(self, self.ID_CLOSE, self.OnCloseButton)
  1713.         EVT_BUTTON(self, self.ID_ADD, self.OnNewButton)
  1714.         EVT_BUTTON(self, self.ID_DELETE, self.OnDeleteButton)
  1715.         EVT_BUTTON(self, self.ID_HELP, (lambda _: wxGetApp().displayhelpid(helpids.ID_EDITING_CALENDAR_EVENTS)))
  1716.         EVT_BUTTON(self, self.ID_PREV, self.OnPrevDayButton)
  1717.         EVT_BUTTON(self, self.ID_NEXT, self.OnNextDayButton)
  1718.         EVT_CLOSE(self, self.OnCloseWindow)
  1719.         self.entries = []
  1720.         self.entrymap = []
  1721.         self.dirty = None
  1722.         self.ignoredirty = False
  1723.         self.setdirty(False)
  1724.  
  1725.     
  1726.     def AskAboutRepeatDelete(self):
  1727.         return self._AskAboutRecurringEvent('Delete recurring event?', 'Do you want to delete all the recurring events, or just this one?', 'Delete')
  1728.  
  1729.     
  1730.     def AskAboutRepeatChange(self):
  1731.         return self._AskAboutRecurringEvent('Change recurring event?', 'Do you want to change all the recurring events, or just this one?', 'Change')
  1732.  
  1733.     
  1734.     def _AskAboutRecurringEvent(self, caption, text, prefix):
  1735.         dlg = RecurringDialog(self, caption, text, prefix)
  1736.         res = dlg.ShowModal()
  1737.         dlg.Destroy()
  1738.         if res == dlg.ID_THIS:
  1739.             return self.ANSWER_THIS
  1740.         
  1741.         if res == dlg.ID_ALL:
  1742.             return self.ANSWER_ORIGINAL
  1743.         
  1744.         if res == dlg.ID_CANCEL:
  1745.             return self.ANSWER_CANCEL
  1746.         
  1747.  
  1748.     
  1749.     def OnListBoxItem(self, _ = None):
  1750.         self.updatefields(self.getcurrententry())
  1751.         self.setdirty(False)
  1752.         self.FindWindowById(self.ID_DELETE).Enable(True)
  1753.  
  1754.     
  1755.     def getcurrententry(self):
  1756.         return self.getentry(self.listbox.GetSelection())
  1757.  
  1758.     
  1759.     def getentry(self, num):
  1760.         return self.entries[self.entrymap[num]]
  1761.  
  1762.     
  1763.     def OnSaveButton(self, _ = None):
  1764.         for x in ('start', 'end'):
  1765.             if not self.fields[x].IsValid():
  1766.                 self.fields[x].SetFocus()
  1767.                 wxBell()
  1768.                 return None
  1769.                 continue
  1770.         
  1771.         start = self.fields['start'].GetValue()
  1772.         end = self.fields['end'].GetValue()
  1773.         if not end[0] < start[0]:
  1774.             if not end[0] == start[0] and end[1] < start[1]:
  1775.                 if not end[0] == start[0] and end[1] == start[1] and end[2] < start[2]:
  1776.                     if end[0] == start[0] and end[1] == start[1] and end[2] == start[2] and end[3] < start[3] and end[0] == start[0] and end[1] == start[1] and end[2] == start[2] and end[3] == start[3] and end[4] < start[4]:
  1777.                         dlg = wxMessageDialog(self, 'End date and time is before start!', 'Time Travel Attempt Detected', wxOK | wxICON_EXCLAMATION)
  1778.                         dlg.ShowModal()
  1779.                         dlg.Destroy()
  1780.                         self.fields['end'].SetFocus()
  1781.                         return None
  1782.                     
  1783.         entry = self.getcurrententry()
  1784.         res = self.ANSWER_ORIGINAL
  1785.         if entry['repeat'] is not None:
  1786.             res = self.AskAboutRepeatChange()
  1787.             if res == self.ANSWER_CANCEL:
  1788.                 return None
  1789.             
  1790.         
  1791.         if res == self.ANSWER_ORIGINAL:
  1792.             newentry = copy.copy(entry)
  1793.             newentry['changeserial'] = entry['changeserial'] + 1
  1794.         else:
  1795.             newentry = self.cw.newentryfactory(*self.date)
  1796.         for f in self.fields:
  1797.             control = self.fields[f]
  1798.             if isinstance(control, DVDateTimeControl):
  1799.                 if res == self.ANSWER_ORIGINAL:
  1800.                     d = control.GetValue()[0:3]
  1801.                 else:
  1802.                     d = self.date
  1803.                 v = list(d) + list(control.GetValue())[3:]
  1804.             else:
  1805.                 v = control.GetValue()
  1806.             if f == 'repeat' and res == self.ANSWER_THIS:
  1807.                 v = None
  1808.             
  1809.             newentry[f] = v
  1810.         
  1811.         newentry['daybitmap'] = self.cw.getdaybitmap(newentry['start'], newentry['repeat'])
  1812.         if res == self.ANSWER_ORIGINAL:
  1813.             self.cw.ChangeEntry(entry, newentry)
  1814.         else:
  1815.             self.cw.DeleteEntryRepeat(entry, *self.date)
  1816.             self.cw.AddEntry(newentry)
  1817.         self.setdirty(False)
  1818.         date = tuple(newentry['start'][:3])
  1819.         if tuple(self.date) != date:
  1820.             self.cw.showday(*date)
  1821.             self.cw.setselection(*date)
  1822.             self.setdate(*date)
  1823.         else:
  1824.             self.refreshentries()
  1825.         self.updatelistbox(newentry['pos'])
  1826.  
  1827.     
  1828.     def OnPrevDayButton(self, _):
  1829.         (y, m, d) = self.date
  1830.         (y, m, d) = calendarcontrol.normalizedate(y, m, d - 1)
  1831.         self.setdate(y, m, d)
  1832.         self.cw.setday(y, m, d)
  1833.  
  1834.     
  1835.     def OnNextDayButton(self, _):
  1836.         (y, m, d) = self.date
  1837.         (y, m, d) = calendarcontrol.normalizedate(y, m, d + 1)
  1838.         self.setdate(y, m, d)
  1839.         self.cw.setday(y, m, d)
  1840.  
  1841.     
  1842.     def OnNewButton(self, _ = None):
  1843.         entry = self.cw.newentryfactory(*self.date)
  1844.         self.cw.AddEntry(entry)
  1845.         self.refreshentries()
  1846.         self.updatelistbox(entry['pos'])
  1847.  
  1848.     
  1849.     def OnRevertButton(self, _ = None):
  1850.         self.OnListBoxItem()
  1851.  
  1852.     
  1853.     def OnDeleteButton(self, _ = None):
  1854.         entry = self.getcurrententry()
  1855.         res = self.ANSWER_ORIGINAL
  1856.         if entry['repeat'] is not None:
  1857.             res = self.AskAboutRepeatDelete()
  1858.             if res == self.ANSWER_CANCEL:
  1859.                 return None
  1860.             
  1861.         
  1862.         enum = self.listbox.GetSelection()
  1863.         if enum + 1 < len(self.entrymap):
  1864.             newpos = self.getentry(enum + 1)['pos']
  1865.         elif enum - 1 >= 0:
  1866.             newpos = self.getentry(enum - 1)['pos']
  1867.         else:
  1868.             newpos = None
  1869.         if res == self.ANSWER_ORIGINAL:
  1870.             self.cw.DeleteEntry(entry)
  1871.         else:
  1872.             self.cw.DeleteEntryRepeat(entry, *self.date)
  1873.         self.refreshentries()
  1874.         self.updatelistbox(newpos)
  1875.  
  1876.     
  1877.     def OnCloseWindow(self, event):
  1878.         if self.FindWindowById(self.ID_CLOSE).IsEnabled():
  1879.             self.Show(False)
  1880.         elif event.CanVeto():
  1881.             event.Veto()
  1882.             wxBell()
  1883.         
  1884.  
  1885.     
  1886.     def OnCloseButton(self, _ = None):
  1887.         self.Show(False)
  1888.  
  1889.     
  1890.     def setdate(self, year, month, day):
  1891.         d = time.strftime('%A %d %B %Y', (year, month, day, 0, 0, 0, calendar.weekday(year, month, day), 1, 0))
  1892.         self.date = (year, month, day)
  1893.         self.title.SetLabel(d)
  1894.         self.refreshentries()
  1895.         self.updatelistbox()
  1896.         self.updatefields(None)
  1897.  
  1898.     
  1899.     def refreshentries(self):
  1900.         self.entries = self.cw.getentrydata(*self.date)
  1901.  
  1902.     
  1903.     def updatelistbox(self, entrytoselect = None):
  1904.         self.listbox.Clear()
  1905.         selectitem = -1
  1906.         self.entrymap = []
  1907.         for index, entry in zip(range(len(self.entries)), self.entries):
  1908.             e = (entry['start'][3:5], entry['end'][3:5], entry['description'], entry['pos'], index)
  1909.             self.entrymap.append(e)
  1910.         
  1911.         self.entrymap.sort()
  1912.         self.entrymap = [ index for ign0, ign1, ign2, ign3, index in self.entrymap ]
  1913.         for curpos, index in zip(range(len(self.entrymap)), self.entrymap):
  1914.             e = self.entries[index]
  1915.             hr = e['start'][3]
  1916.             ap = 'am'
  1917.             if hr >= 12:
  1918.                 ap = 'pm'
  1919.                 hr -= 12
  1920.             
  1921.             if hr == 0:
  1922.                 hr = 12
  1923.             
  1924.             str = '%2d:%02d %s' % (hr, e['start'][4], ap)
  1925.             str += ' ' + e['description']
  1926.             self.listbox.Append(str)
  1927.         
  1928.         if selectitem >= 0:
  1929.             self.listbox.SetSelection(selectitem)
  1930.             self.OnListBoxItem()
  1931.         else:
  1932.             self.updatefields(None)
  1933.         if len(self.entries) == 0:
  1934.             self.FindWindowById(self.ID_DELETE).Enable(False)
  1935.         
  1936.  
  1937.     
  1938.     def updatefields(self, entry):
  1939.         self.ignoredirty = True
  1940.         active = True
  1941.         if entry is None:
  1942.             for i in self.fields:
  1943.                 self.fields[i].SetValue(None)
  1944.             
  1945.             active = False
  1946.         else:
  1947.             for i in self.fieldnames:
  1948.                 self.fields[i].SetValue(entry[i])
  1949.             
  1950.         for i in self.fields:
  1951.             self.fields[i].Enable(active)
  1952.         
  1953.         self.ignoredirty = False
  1954.  
  1955.     
  1956.     def OnMakeDirty(self, _ = None):
  1957.         self.setdirty(True)
  1958.  
  1959.     
  1960.     def setdirty(self, val):
  1961.         if self.ignoredirty:
  1962.             return None
  1963.         
  1964.         self.dirty = val
  1965.         if self.dirty:
  1966.             self.FindWindowById(self.ID_SAVE).Enable(True)
  1967.             self.FindWindowById(self.ID_REVERT).Enable(True)
  1968.             self.FindWindowById(self.ID_DELETE).Enable(True)
  1969.             self.FindWindowById(self.ID_CLOSE).Enable(False)
  1970.             self.FindWindowById(self.ID_PREV).Enable(False)
  1971.             self.FindWindowById(self.ID_NEXT).Enable(False)
  1972.             self.FindWindowById(self.ID_ADD).Enable(False)
  1973.             self.FindWindowById(self.ID_LISTBOX).Enable(False)
  1974.         else:
  1975.             self.FindWindowById(self.ID_SAVE).Enable(False)
  1976.             self.FindWindowById(self.ID_REVERT).Enable(False)
  1977.             self.FindWindowById(self.ID_CLOSE).Enable(True)
  1978.             self.FindWindowById(self.ID_DELETE).Enable(len(self.entries) > 0)
  1979.             self.FindWindowById(self.ID_PREV).Enable(True)
  1980.             self.FindWindowById(self.ID_NEXT).Enable(True)
  1981.             self.FindWindowById(self.ID_ADD).Enable(True)
  1982.             self.FindWindowById(self.ID_LISTBOX).Enable(True)
  1983.  
  1984.  
  1985.  
  1986. class DVDateTimeControl(wxPanel):
  1987.     
  1988.     def __init__(self, parent, id):
  1989.         f = 'EUDATETIMEYYYYMMDD.HHMM'
  1990.         wxPanel.__init__(self, parent, -1)
  1991.         self.c = wxMaskedTextCtrl(self, id, '', autoformat = f)
  1992.         bs = wxBoxSizer(wxHORIZONTAL)
  1993.         bs.Add(self.c, 0, wxEXPAND)
  1994.         self.SetSizer(bs)
  1995.         self.SetAutoLayout(True)
  1996.         bs.Fit(self)
  1997.         EVT_TEXT(self.c, id, parent.OnMakeDirty)
  1998.  
  1999.     
  2000.     def SetValue(self, v):
  2001.         if v is None:
  2002.             self.c.SetValue('')
  2003.             return None
  2004.         
  2005.         ap = 'A'
  2006.         v = list(v)
  2007.         if v[3] > 12:
  2008.             v[3] -= 12
  2009.             ap = 'P'
  2010.         elif v[3] == 0:
  2011.             v[3] = 12
  2012.         elif v[3] == 12:
  2013.             ap = 'P'
  2014.         
  2015.         v = v + [
  2016.             ap]
  2017.         str = '%04d%02d%02d%02d%02d%s' % tuple(v)
  2018.         self.c.SetValue(str)
  2019.         self.c.Refresh()
  2020.  
  2021.     
  2022.     def GetValue(self):
  2023.         str = self.c.GetValue()
  2024.         digits = '0123456789'
  2025.         res = []
  2026.         val = None
  2027.         for i in str:
  2028.             if i in digits:
  2029.                 if val is None:
  2030.                     val = 0
  2031.                 
  2032.                 val *= 10
  2033.                 val += int(i)
  2034.                 continue
  2035.             if val is not None:
  2036.                 res.append(val)
  2037.                 val = None
  2038.                 continue
  2039.         
  2040.         if str[-2] == 'P' or str[-2] == 'p':
  2041.             if res[3] != 12:
  2042.                 res[3] += 12
  2043.             
  2044.         elif res[3] == 12:
  2045.             res[3] = 0
  2046.         
  2047.         return res
  2048.  
  2049.     
  2050.     def IsValid(self):
  2051.         return self.c.IsValid()
  2052.  
  2053.  
  2054.  
  2055. class DVRepeatControl(wxChoice):
  2056.     vals = [
  2057.         None,
  2058.         'daily',
  2059.         'monfri',
  2060.         'weekly',
  2061.         'monthly',
  2062.         'yearly']
  2063.     desc = [
  2064.         'None',
  2065.         'Daily',
  2066.         'Mon - Fri',
  2067.         'Weekly',
  2068.         'Monthly',
  2069.         'Yearly']
  2070.     
  2071.     def __init__(self, parent, id):
  2072.         wxChoice.__init__(self, parent, id, choices = self.desc)
  2073.         EVT_CHOICE(self, id, parent.OnMakeDirty)
  2074.  
  2075.     
  2076.     def SetValue(self, v):
  2077.         self.SetSelection(self.vals.index(v))
  2078.  
  2079.     
  2080.     def GetValue(self):
  2081.         s = self.GetSelection()
  2082.         if s < 0:
  2083.             s = 0
  2084.         
  2085.         return self.vals[s]
  2086.  
  2087.  
  2088.  
  2089. class DVIntControl(wxIntCtrl):
  2090.     
  2091.     def __init__(self, parent, id):
  2092.         wxIntCtrl.__init__(self, parent, id, limited = True)
  2093.         EVT_INT(self, id, parent.OnMakeDirty)
  2094.  
  2095.     
  2096.     def SetValue(self, v):
  2097.         if v is None:
  2098.             v = -1
  2099.         
  2100.         wxIntCtrl.SetValue(self, v)
  2101.  
  2102.  
  2103.  
  2104. class DVTextControl(wxTextCtrl):
  2105.     
  2106.     def __init__(self, parent, id, value = ''):
  2107.         if value is None:
  2108.             value = ''
  2109.         
  2110.         wxTextCtrl.__init__(self, parent, id, value)
  2111.         EVT_TEXT(self, id, parent.OnMakeDirty)
  2112.  
  2113.     
  2114.     def SetValue(self, v):
  2115.         if v is None:
  2116.             v = ''
  2117.         
  2118.         wxTextCtrl.SetValue(self, v)
  2119.  
  2120.  
  2121.  
  2122. class RecurringDialog(wxDialog):
  2123.     ID_THIS = 1
  2124.     ID_ALL = 2
  2125.     ID_CANCEL = 3
  2126.     ID_HELP = 4
  2127.     
  2128.     def __init__(self, parent, caption, text, prefix):
  2129.         wxDialog.__init__(self, parent, -1, caption, style = wxCAPTION)
  2130.         vbs = wxBoxSizer(wxVERTICAL)
  2131.         t = wxStaticText(self, -1, text)
  2132.         vbs.Add(t, 1, wxEXPAND | wxALL, 10)
  2133.         vbs.Add(wxStaticLine(self, -1), 0, wxEXPAND | wxTOP | wxBOTTOM, 3)
  2134.         buttonsizer = wxBoxSizer(wxHORIZONTAL)
  2135.         for id, label in ((self.ID_THIS, '%s %s' % (prefix, 'this')), (self.ID_ALL, '%s %s' % (prefix, 'all')), (self.ID_CANCEL, 'Cancel'), (self.ID_HELP, 'Help')):
  2136.             b = wxButton(self, id, label)
  2137.             EVT_BUTTON(self, id, self._onbutton)
  2138.             buttonsizer.Add(b, 5, wxALIGN_CENTER | wxALL, 5)
  2139.         
  2140.         vbs.Add(buttonsizer, 0, wxEXPAND | wxALL, 2)
  2141.         self.SetSizer(vbs)
  2142.         self.SetAutoLayout(True)
  2143.         vbs.Fit(self)
  2144.  
  2145.     
  2146.     def _onbutton(self, evt):
  2147.         if evt.GetId() == self.ID_HELP:
  2148.             pass
  2149.         else:
  2150.             self.EndModal(evt.GetId())
  2151.  
  2152.  
  2153.  
  2154. class MyFixedScrolledMessageDialog(wxDialog):
  2155.     
  2156.     def __init__(self, parent, msg, caption, helpid, pos = wxDefaultPosition, size = (850, 600)):
  2157.         wxDialog.__init__(self, parent, -1, caption, pos, size)
  2158.         text = wxTextCtrl(self, 1, style = wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2 | wxNO_FULL_REPAINT_ON_RESIZE | wxTE_DONTWRAP)
  2159.         f = wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)
  2160.         ta = wxTextAttr(font = f)
  2161.         text.SetDefaultStyle(ta)
  2162.         text.AppendText(msg)
  2163.         text.SetInsertionPoint(0)
  2164.         text.ShowPosition(text.XYToPosition(0, 0))
  2165.         vbs = wxBoxSizer(wxVERTICAL)
  2166.         vbs.Add(text, 1, wxEXPAND | wxALL, 10)
  2167.         vbs.Add(self.CreateButtonSizer(wxOK | wxHELP), 0, wxALIGN_RIGHT | wxALL, 10)
  2168.         self.SetSizer(vbs)
  2169.         self.SetAutoLayout(True)
  2170.         EVT_BUTTON(self, wxID_HELP, (lambda _, helpid = helpid: wxGetApp().displayhelpid(helpid)))
  2171.  
  2172.  
  2173. import StringIO
  2174. import traceback
  2175.  
  2176. class ExceptionDialog(MyFixedScrolledMessageDialog):
  2177.     
  2178.     def __init__(self, frame, exception, title = 'Exception'):
  2179.         s = StringIO.StringIO()
  2180.         s.write('An unexpected exception has occurred.\nPlease see the help for details on what to do.\n\n')
  2181.         if hasattr(exception, 'gui_exc_info'):
  2182.             traceback.print_exception(exception.gui_exc_info[0], exception.gui_exc_info[1], exception.gui_exc_info[2], file = s)
  2183.         else:
  2184.             s.write('Exception with no extra info.\n%s\n' % (exception.str(),))
  2185.         MyFixedScrolledMessageDialog.__init__(self, frame, s.getvalue(), title, helpids.ID_EXCEPTION_DIALOG)
  2186.  
  2187.  
  2188.  
  2189. class MyStatusBar(wxStatusBar):
  2190.     
  2191.     def __init__(self, parent, id = -1):
  2192.         wxStatusBar.__init__(self, parent, id)
  2193.         self.sizechanged = False
  2194.         EVT_SIZE(self, self.OnSize)
  2195.         EVT_IDLE(self, self.OnIdle)
  2196.         self.gauge = wxGauge(self, 1000, 1)
  2197.         self.SetFieldsCount(4)
  2198.         self.SetStatusWidths([
  2199.             200,
  2200.             -5,
  2201.             180,
  2202.             -20])
  2203.         self.Reposition()
  2204.  
  2205.     
  2206.     def OnSize(self, _):
  2207.         self.Reposition()
  2208.         self.sizechanged = True
  2209.  
  2210.     
  2211.     def OnIdle(self, _):
  2212.         if self.sizechanged:
  2213.             self.Reposition()
  2214.         
  2215.  
  2216.     
  2217.     def Reposition(self):
  2218.         rect = self.GetFieldRect(2)
  2219.         self.gauge.SetPosition(wxPoint(rect.x + 2, rect.y + 2))
  2220.         self.gauge.SetSize(wxSize(rect.width - 4, rect.height - 4))
  2221.         self.sizeChanged = False
  2222.  
  2223.     
  2224.     def progressminor(self, pos, max, desc = ''):
  2225.         self.gauge.SetRange(max)
  2226.         self.gauge.SetValue(pos)
  2227.         self.SetStatusText(desc, 3)
  2228.  
  2229.     
  2230.     def progressmajor(self, pos, max, desc = ''):
  2231.         self.progressminor(0, 1)
  2232.         if len(desc) and max:
  2233.             str = '%d/%d %s' % (pos + 1, max, desc)
  2234.         else:
  2235.             str = desc
  2236.         self.SetStatusText(str, 1)
  2237.  
  2238.  
  2239.  
  2240. class AlertDialogWithHelp(wxDialog):
  2241.     
  2242.     def __init__(self, parent, message, caption, helpfn, style = wxDEFAULT_DIALOG_STYLE, icon = wxICON_EXCLAMATION):
  2243.         wxDialog.__init__(self, parent, -1, caption, style = style | wxDEFAULT_DIALOG_STYLE)
  2244.         p = self
  2245.         hbs = wxBoxSizer(wxHORIZONTAL)
  2246.         hbs.Add(wxStaticBitmap(p, -1, wxArtProvider_GetBitmap(self.icontoart(icon), wxART_MESSAGE_BOX)), 0, wxCENTER | wxALL, 10)
  2247.         hbs.Add(wxStaticText(p, -1, message), 1, wxCENTER | wxALL, 10)
  2248.         buttsizer = self.CreateButtonSizer(wxHELP | style)
  2249.         vbs = wxBoxSizer(wxVERTICAL)
  2250.         vbs.Add(hbs, 1, wxEXPAND | wxALL, 10)
  2251.         vbs.Add(buttsizer, 0, wxCENTER | wxALL, 10)
  2252.         self.SetSizer(vbs)
  2253.         self.SetAutoLayout(True)
  2254.         vbs.Fit(self)
  2255.         EVT_BUTTON(self, wxID_HELP, helpfn)
  2256.  
  2257.     
  2258.     def icontoart(self, id):
  2259.         if id & wxICON_EXCLAMATION:
  2260.             return wxART_WARNING
  2261.         
  2262.         if id & wxICON_INFORMATION:
  2263.             return wxART_INFORMATION
  2264.         
  2265.         return wxART_INFORMATION
  2266.  
  2267.  
  2268.  
  2269. class AnotherDialog(wxDialog):
  2270.     
  2271.     def __init__(self, parent, message, caption, buttons, helpfn = None, style = wxDEFAULT_DIALOG_STYLE, icon = wxICON_EXCLAMATION):
  2272.         wxDialog.__init__(self, parent, -1, caption, style = style)
  2273.         p = self
  2274.         hbs = wxBoxSizer(wxHORIZONTAL)
  2275.         hbs.Add(wxStaticBitmap(p, -1, wxArtProvider_GetBitmap(self.icontoart(icon), wxART_MESSAGE_BOX)), 0, wxCENTER | wxALL, 10)
  2276.         hbs.Add(wxStaticText(p, -1, message), 1, wxCENTER | wxALL, 10)
  2277.         buttsizer = wxBoxSizer(wxHORIZONTAL)
  2278.         for label, id in buttons:
  2279.             buttsizer.Add(wxButton(self, id, label), 0, wxALL | wxALIGN_CENTER, 5)
  2280.             if id != wxID_HELP:
  2281.                 EVT_BUTTON(self, id, self.OnButton)
  2282.                 continue
  2283.             EVT_BUTTON(self, wxID_HELP, helpfn)
  2284.         
  2285.         vbs = wxBoxSizer(wxVERTICAL)
  2286.         vbs.Add(hbs, 1, wxEXPAND | wxALL, 10)
  2287.         vbs.Add(buttsizer, 0, wxCENTER | wxALL, 10)
  2288.         self.SetSizer(vbs)
  2289.         self.SetAutoLayout(True)
  2290.         vbs.Fit(self)
  2291.  
  2292.     
  2293.     def OnButton(self, event):
  2294.         self.EndModal(event.GetId())
  2295.  
  2296.     
  2297.     def icontoart(self, id):
  2298.         if id & wxICON_EXCLAMATION:
  2299.             return wxART_WARNING
  2300.         
  2301.         if id & wxICON_INFORMATION:
  2302.             return wxART_INFORMATION
  2303.         
  2304.         return wxART_INFORMATION
  2305.  
  2306.  
  2307.